Fix JsonSchemaExporter dropping nullability for nullable floating-point composition schemas#129530
Conversation
Co-authored-by: eiriktsarpalis <2813363+eiriktsarpalis@users.noreply.github.com>
|
Tagging subscribers to this area: @dotnet/area-system-text-json |
eiriktsarpalis
left a comment
There was a problem hiding this comment.
@copilot This doesn't look right.
Co-authored-by: eiriktsarpalis <2813363+eiriktsarpalis@users.noreply.github.com>
Agreed — the original approach was wrong. I've reworked it in {"anyOf":[{"type":["number","null"]},{"enum":["NaN","Infinity","-Infinity"]}]}This also handles the empty/type-less |
…, revert MakeNullable Co-authored-by: eiriktsarpalis <2813363+eiriktsarpalis@users.noreply.github.com>
Co-authored-by: eiriktsarpalis <10833894+eiriktsarpalis@users.noreply.github.com>
Introduced a virtual property `IsIeeeFloatingPointConverter` on `JsonConverter`, overridden to `true` in `DoubleConverter`, `SingleConverter`, and `HalfConverter`. Updated `JsonSchemaExporter` to check this property instead of performing brittle element type checks, preventing false positives from nullable struct unions. Replaced the boolean foundNumberBranch with a Debug.Assert that checks the list before iteration. Added test coverage for nullable struct unions to ensure nullability is preserved without affecting IEEE floating-point schema generation. Co-authored-by: eiriktsarpalis <16040868+eiriktsarpalis@users.noreply.github.com>
Replaced the IStructDiscriminatedUnion polymorphic interface test with a proper C# union type (MyUnion(int, string)) as requested. The union type test validates that nullable struct unions preserve nullability in anyOf schemas without relying on the IEEE floating-point converter path. Co-authored-by: eiriktsarpalis <2813363+eiriktsarpalis@users.noreply.github.com>
…E float check Following review feedback, the nullable anyOf handling now: 1. Only executes for IEEE floating-point converters with AllowNamedFloatingPointLiterals 2. Asserts that anyOf schema exists (as it always should for this specific case) 3. Removes the unreachable else branch that was never hit by any test case The MyUnion? test case and type declaration have been removed because union schema generation handles nullable cases internally via caseInfo.IsNullable, so the nullable wrapper code path is never exercised for unions. Co-authored-by: eiriktsarpalis <2813363+eiriktsarpalis@users.noreply.github.com>
JsonSchemaExporteromitted null-acceptance for CLR-nullable types (double?,float?,Half?) whose schema is emitted as ananyOfcomposition — which happens for IEEE floating-point types underJsonNumberHandling.AllowNamedFloatingPointLiterals. The same property exports correctly as{"type":["number","null"]}under default number handling, so adouble?was advertised to downstream JSON-Schema/OpenAPI consumers as a non-nullable number.Description
JsonSchema.MakeNullableonly addsJsonSchemaType.Nullwhen the schema carries a concretetypekeyword. Composition schemas (anyOf) haveType == Any, so nullable wrappers over floating-pointanyOfschemas could lose nullability.internal virtual bool IsIeeeFloatingPointConverterproperty onJsonConverter, overridden totrueinDoubleConverter,SingleConverter, andHalfConverter. Updated the nullable-value-type path inJsonSchemaExporter.MapJsonSchemaCoreto check both this property and the presence ofAllowNamedFloatingPointLiteralsin the effective number handling. When both conditions are met, null is folded into the numeric branch'stypekeyword ("type": ["number","null"]). AddedDebug.Assertstatements to validate the expected anyOf schema shape for IEEE floating-point types withAllowNamedFloatingPointLiterals.double?,float?,Half?, and a POCO with nullable floating-point properties under globalAllowNamedFloatingPointLiterals, across reflection and source-gen test contexts.Resulting export for a nullable property: